package com.example.demo_mysql_mybatisplus.util.controller.advicer.core;

import com.example.demo_mysql_mybatisplus.util.controller.advicer.ErrorEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletResponse;

/**
 * 统一封装Controller的返回值
 */
@Slf4j
@ControllerAdvice
@ConditionalOnWebApplication
class ResponseBodyAdviceEx implements ResponseBodyAdvice<Object> {

    final static String[] CONTENT_TYPES = {"application/octet\\-stream", "application/msword", "application/vnd.ms\\-excel", "application/pdf", "application/csv", "image/"};
    final static String CONTENT_TYPE_REGEX = "^[" + String.join("|", CONTENT_TYPES) + "].*";

    @ExceptionHandler(value = Throwable.class)
    @ResponseBody
    public RestResponse errorHandler(Throwable throwable) {
        RestException rex;
        if (throwable instanceof RestException) {
            rex = (RestException) throwable;
        } else {
            rex = new RestException(ErrorEnum.SYSTEM_ERROR.getCode()
                    ,ErrorEnum.SYSTEM_ERROR.getDesc()+"("+throwable.getMessage()+")");
        }

        String stackTrace  = RestException.getStackTrace(throwable) ;
        log.error( "error info: "+rex.getCode()+" of "+rex.getDesc()+" ==》\r\n"+ stackTrace );

        return new RestResponse(rex.getCode(), rex.getDesc() ,null ,stackTrace);
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true ;
    }

    @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request,
                                  ServerHttpResponse response) {

        // api无返回值（void），不会走这个函数

        // 文件类型的响应不包装
        if (response instanceof ServletServerHttpResponse && body == null) {
            HttpServletResponse resp = ((ServletServerHttpResponse) response).getServletResponse();
            if (null != resp) {
                String contentType = resp.getContentType();
                if (null != contentType && contentType.matches(CONTENT_TYPE_REGEX)) {
                    return body;
                }
            }
        }

        if (body instanceof RestResponse) {
            return body ;
        } else {
            return new RestResponse(ErrorEnum.SUCCESS.getCode(),ErrorEnum.SUCCESS.getDesc() ,body ,null);
        }
    }

}